//	Project: Handle Template Library
//	Author:  Paul Bludov
//	Date:	 2008-12-07
//
//	Description:
//		C++ wrapper for Win32 service HANDLE.
//
//	Update History:
//		None
//
//@//////////////////////////////////////////////////////////////////////////

#ifndef __HTLSVC_H__
#define __HTLSVC_H__

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#pragma warning(push)
#pragma warning(disable: 4127) // conditional expression is constant

#include "htlhandle.h"

/////////////////////////////////////////////////////////////////////////////
// Classes in this file
//
// CSCManagerT<t_bManaged>
// CServiceT<t_bManaged>
//

namespace HTL
{

/////////////////////////////////////////////////////////////////////////////

inline bool IsValidSCManager
	( IN SC_HANDLE h
	)
{
#ifdef _DEBUG
	if (NULL != h)
	{
		DWORD nError = ::GetLastError();
		QUERY_SERVICE_LOCK_STATUS status;
		DWORD cbBytesNeeded = 0;

		_ASSERTE(::QueryServiceLockStatus(h, &status, NULL, &cbBytesNeeded)
			|| ::GetLastError() != ERROR_INVALID_HANDLE);
		::SetLastError(nError);
	}
#endif
	return NULL != h;
}

inline bool IsValidService
	( IN SC_HANDLE h
	)
{
#ifdef _DEBUG
	if (NULL != h)
	{
		DWORD nError = ::GetLastError();
		SERVICE_STATUS status;
		_ASSERTE(::QueryServiceStatus(h, &status)
			|| ::GetLastError() != ERROR_INVALID_HANDLE);
		::SetLastError(nError);
	}
#endif
	return NULL != h;
}


/////////////////////////////////////////////////////////////////////////////
// CSCManager

template<bool t_bManaged>
class CSCManagerT
{
public:
// Data members
	SC_HANDLE m_h;

// Constructor/destructor/operators
	CSCManagerT()
		: m_h(NULL)
	{ }

	explicit CSCManagerT
		( IN SC_HANDLE h
		)
		: m_h(h)
	{
		_ASSERTE(IsValid());
	}

	CSCManagerT
		( const CSCManagerT<true>& rh
		)
		: m_h(NULL)
	{
		// Avoid using this method,
		// use Attach(other.Detach() instead

		m_h = rh.m_h;
	}

	CSCManagerT
		( const CSCManagerT<false>& rh
		)
		: m_h(NULL)
	{
		// Avoid using this method,
		// use Attach(other.Detach() instead

		m_h = rh.m_h;
	}

	CSCManagerT
		( IN LPCSTR lpMachineName
		, IN LPCSTR lpDatabaseName
		, IN DWORD  dwDesiredAccess
		)
		: m_h(NULL)
	{
		Open(lpMachineName, lpDatabaseName, dwDesiredAccess);
		_ASSERTE(IsValid());
	}

	CSCManagerT
		( IN LPCWSTR lpMachineName
		, IN LPCWSTR lpDatabaseName
		, IN DWORD   dwDesiredAccess
		)
		: m_h(NULL)
	{
		Open(lpMachineName, lpDatabaseName, dwDesiredAccess);
		_ASSERTE(IsValid());
	}

	explicit CSCManagerT
		( IN DWORD  dwDesiredAccess
		)
		: m_h(NULL)
	{
		Open(dwDesiredAccess);
		_ASSERTE(IsValid());
	}

	~CSCManagerT()
	{
		if (t_bManaged)
			Close();
	}

	bool IsValid() const
	{
		return HTL::IsValidSCManager(m_h);
	}

	void Close()
	{
		// Close the handle
		if (IsValid())
		{
			BOOL b;
			b = ::CloseServiceHandle(m_h);
			_ASSERTE(b);
		}
		m_h = NULL;
	}

	bool operator!() const
	{
		return !IsValid();
	}

	operator SC_HANDLE() const
	{
		return m_h;
	}

	operator bool() const
	{
		return IsValid();
	}

	SC_HANDLE* operator&()
	{
		// The assert on operator& usually indicates a bug.	If this is really
		// what is needed, take the address of the m_h member explicitly

		_ASSERTE(!IsValid());
		return &m_h;
	}

	CSCManagerT<t_bManaged>& operator=
		( SC_HANDLE h
		)
	{
		// Try m_SCManager.Attach(other.Detach())
		// if you got an assertion here.

		_ASSERTE(!IsValid() || false == t_bManaged);
		m_h = h;
		return *this;
	}

	CSCManagerT<t_bManaged>& operator=
		( const CSCManagerT<true>& other
		)
	{
		// Avoid using this method,
		// use Attach(other.Detach() instead

		_ASSERTE(!IsValid() || false == t_bManaged);
		m_h = other.m_h;
		return *this;
	}

	CSCManagerT<t_bManaged>& operator=
		( const CSCManagerT<false>& other
		)
	{
		// Avoid using this method,
		// use Attach(other.Detach() instead

		_ASSERTE(!IsValid() || false == t_bManaged);
		m_h = other.m_h;
	}

	void Attach
		( IN SC_HANDLE h
		)
	{
		// The main difference between operator= & Attach
		// that Attach releases the handle.

		if (t_bManaged && IsValid())
			::CloseServiceHandle(m_h);
		m_h = h;
	}

	SC_HANDLE Detach()
	{
		SC_HANDLE h = m_h;
		m_h = NULL;
		return h;
	}

	SC_HANDLE Open
		( IN LPCSTR lpMachineName
		, IN LPCSTR lpDatabaseName
		, IN DWORD  dwDesiredAccess
		)
	{
		_ASSERTE(!IsValid());
		m_h = ::OpenSCManagerA(lpMachineName, lpDatabaseName, dwDesiredAccess);
		return m_h;
	}

	SC_HANDLE Open
		( IN LPCWSTR lpMachineName
		, IN LPCWSTR lpDatabaseName
		, IN DWORD   dwDesiredAccess
		)
	{
		_ASSERTE(!IsValid());
		m_h = ::OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess);
		return m_h;
	}

	SC_HANDLE Open
		( IN DWORD dwDesiredAccess
		)
	{
		_ASSERTE(!IsValid());
		m_h = ::OpenSCManagerW(NULL, NULL, dwDesiredAccess);
		return m_h;
	}

	SC_HANDLE CreateService
		( IN LPCSTR lpServiceName
		, IN LPCSTR lpDisplayName
		, IN DWORD dwDesiredAccess
		, IN DWORD dwServiceType
		, IN DWORD dwStartType
		, IN DWORD dwErrorControl
		, IN LPCSTR lpBinaryPathName = NULL
		, IN LPCSTR lpLoadOrderGroup = NULL
		, OUT LPDWORD lpdwTagId = NULL
		, IN LPCSTR lpDependencies = NULL
		, IN LPCSTR lpServiceStartName = NULL
		, IN LPCSTR lpPassword = NULL
		)
	{
		_ASSERTE(lpServiceName);
		_ASSERTE(IsValid());
		return ::CreateServiceA(m_h, lpServiceName, lpDisplayName
			, dwDesiredAccess, dwServiceType, dwStartType
			, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup
			, lpdwTagId, lpDependencies, lpServiceStartName, lpPassword);
	}

	SC_HANDLE CreateService
		( IN LPCSTR lpServiceName
		, IN DWORD dwDesiredAccess
		, IN DWORD dwServiceType
		, IN DWORD dwStartType
		, IN DWORD dwErrorControl
		, IN LPCSTR lpBinaryPathName = NULL
		, IN LPCSTR lpLoadOrderGroup = NULL
		, OUT LPDWORD lpdwTagId = NULL
		, IN LPCSTR lpDependencies = NULL
		, IN LPCSTR lpServiceStartName = NULL
		, IN LPCSTR lpPassword = NULL
		)
	{
		_ASSERTE(lpServiceName);
		_ASSERTE(IsValid());
		return ::CreateServiceA(m_h, lpServiceName, NULL
			, dwDesiredAccess, dwServiceType, dwStartType
			, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup
			, lpdwTagId, lpDependencies, lpServiceStartName, lpPassword);
	}

	SC_HANDLE CreateService
		( IN LPCWSTR lpServiceName
		, IN LPCWSTR lpDisplayName
		, IN DWORD dwDesiredAccess
		, IN DWORD dwServiceType
		, IN DWORD dwStartType
		, IN DWORD dwErrorControl
		, IN LPCWSTR lpBinaryPathName = NULL
		, IN LPCWSTR lpLoadOrderGroup = NULL
		, OUT LPDWORD lpdwTagId = NULL
		, IN LPCWSTR lpDependencies = NULL
		, IN LPCWSTR lpServiceStartName = NULL
		, IN LPCWSTR lpPassword = NULL
		)
	{
		_ASSERTE(lpServiceName);
		_ASSERTE(IsValid());
		return ::CreateServiceW(m_h, lpServiceName, lpDisplayName
			, dwDesiredAccess, dwServiceType, dwStartType
			, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup
			, lpdwTagId, lpDependencies, lpServiceStartName, lpPassword);
	}

	SC_HANDLE CreateService
		( IN LPCWSTR lpServiceName
		, IN DWORD dwDesiredAccess
		, IN DWORD dwServiceType
		, IN DWORD dwStartType
		, IN DWORD dwErrorControl
		, IN LPCWSTR lpBinaryPathName = NULL
		, IN LPCWSTR lpLoadOrderGroup = NULL
		, OUT LPDWORD lpdwTagId = NULL
		, IN LPCWSTR lpDependencies = NULL
		, IN LPCWSTR lpServiceStartName = NULL
		, IN LPCWSTR lpPassword = NULL
		)
	{
		_ASSERTE(lpServiceName);
		_ASSERTE(IsValid());
		return ::CreateServiceW(m_h, lpServiceName, NULL
			, dwDesiredAccess, dwServiceType, dwStartType
			, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup
			, lpdwTagId, lpDependencies, lpServiceStartName, lpPassword);
	}

	SC_HANDLE OpenService
		( IN LPCSTR lpServiceName
		, IN DWORD dwDesiredAccess
		)
	{
		_ASSERTE(lpServiceName);
		_ASSERTE(IsValid());
		return ::OpenServiceA(m_h, lpServiceName, dwDesiredAccess);
	}

	SC_HANDLE OpenService
		( IN LPCWSTR lpServiceName
		, IN DWORD dwDesiredAccess
		)
	{
		_ASSERTE(lpServiceName);
		_ASSERTE(IsValid());
		return ::OpenServiceW(m_h, lpServiceName, dwDesiredAccess);
	}

	BOOL EnumServicesStatus
		( IN DWORD dwServiceType
		, IN DWORD dwServiceState
		, OUT LPENUM_SERVICE_STATUSA lpServices
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		, OUT LPDWORD lpServicesReturned
		, IN OUT LPDWORD lpResumeHandle = NULL
		)
	{
		_ASSERTE(IsValid());
		return EnumServicesStatusA(m_h, dwServiceType, dwServiceState, lpServices
			, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
	}

	BOOL EnumServicesStatus
		( IN DWORD dwServiceType
		, IN DWORD dwServiceState
		, OUT LPENUM_SERVICE_STATUSW lpServices
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		, OUT LPDWORD lpServicesReturned
		, IN OUT LPDWORD lpResumeHandle = NULL
		)
	{
		_ASSERTE(IsValid());
		return EnumServicesStatusW(m_h, dwServiceType, dwServiceState, lpServices
			, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
	}

	BOOL EnumServicesStatusEx
		( IN SC_ENUM_TYPE InfoLevel
		, IN DWORD dwServiceType
		, IN DWORD dwServiceState
		, OUT LPBYTE lpServices
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		, OUT LPDWORD lpServicesReturned
		, IN OUT LPDWORD lpResumeHandle = NULL
		, IN LPCSTR pszGroupName = NULL
		)
	{
		_ASSERTE(IsValid());
		return EnumServicesStatusExA(m_h, InfoLevel, dwServiceType, dwServiceState, lpServices
			, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle, pszGroupName);
	}

	BOOL EnumServicesStatusEx
		( IN SC_ENUM_TYPE InfoLevel
		, IN DWORD dwServiceType
		, IN DWORD dwServiceState
		, OUT LPBYTE lpServices
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		, OUT LPDWORD lpServicesReturned
		, IN OUT LPDWORD lpResumeHandle = NULL
		, IN LPCWSTR pszGroupName = NULL
		)
	{
		_ASSERTE(IsValid());
		return EnumServicesStatusExW(m_h, InfoLevel, dwServiceType, dwServiceState, lpServices
			, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle, pszGroupName);
	}

	BOOL GetServiceKeyName
		( IN LPCSTR lpDisplayName
		, OUT LPSTR lpServiceName
		, IN OUT LPDWORD lpcchBuffer
		)
	{
		_ASSERTE(lpDisplayName);
		_ASSERTE(IsValid());
		return ::GetServiceKeyNameA(m_h, lpDisplayName, lpServiceName, lpcchBuffer);
	}

	BOOL GetServiceKeyName
		( IN LPCWSTR lpDisplayName
		, OUT LPWSTR lpServiceName
		, IN OUT LPDWORD lpcchBuffer
		)
	{
		_ASSERTE(lpDisplayName);
		_ASSERTE(IsValid());
		return ::GetServiceKeyNameW(m_h, lpDisplayName, lpServiceName, lpcchBuffer);
	}

	BOOL GetServiceDisplayName
		( IN LPCSTR lpServiceName
		, OUT LPSTR lpDisplayName
		, IN OUT LPDWORD lpcchBuffer
		)
	{
		_ASSERTE(lpServiceName);
		_ASSERTE(IsValid());
		return ::GetServiceDisplayNameA(m_h, lpServiceName, lpDisplayName, lpcchBuffer);
	}

	BOOL GetServiceDisplayName
		( IN LPCWSTR lpServiceName
		, OUT LPWSTR lpDisplayName
		, IN OUT LPDWORD lpcchBuffer
		)
	{
		_ASSERTE(lpServiceName);
		_ASSERTE(IsValid());
		return ::GetServiceDisplayNameW(m_h, lpServiceName, lpDisplayName, lpcchBuffer);
	}

	SC_LOCK LockServiceDatabase()
	{
		_ASSERTE(IsValid());
		return ::LockServiceDatabase(m_h);
	}

	BOOL UnlockServiceDatabase
		( IN SC_LOCK ScLock
		)
	{
		_ASSERTE(IsValid());
		return ::UnlockServiceDatabase(ScLock);
	}

	BOOL QueryServiceLockStatus
		( OUT LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		)
	{
		_ASSERTE(IsValid());
		return ::QueryServiceLockStatusA(m_h, lpLockStatus, cbBufSize, pcbBytesNeeded);
	}

	BOOL QueryServiceLockStatus
		( OUT LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		)
	{
		_ASSERTE(IsValid());
		return ::QueryServiceLockStatusW(m_h, lpLockStatus, cbBufSize, pcbBytesNeeded);
	}
};

typedef CSCManagerT<true> CSCManager;
typedef CSCManagerT<false> CSCManagerHandle;

/////////////////////////////////////////////////////////////////////////////
// CService

template<bool t_bManaged>
class CServiceT
{
public:
// Data members
	SC_HANDLE m_h;

// Constructor/destructor/operators
	CServiceT()
		: m_h(NULL)
	{ }

	explicit CServiceT
		( IN SC_HANDLE h
		)
		: m_h(h)
	{
		_ASSERTE(IsValid());
	}

	CServiceT
		( const CSCManagerT<true>& rh
		)
		: m_h(NULL)
	{
		// Avoid using this method,
		// use Attach(other.Detach() instead

		m_h = rh.m_h;
	}

	CServiceT
		( const CServiceT<false>& rh
		)
		: m_h(NULL)
	{
		// Avoid using this method,
		// use Attach(other.Detach() instead

		m_h = rh.m_h;
	}

	~CServiceT()
	{
		if (t_bManaged)
			Close();
	}

	bool IsValid() const
	{
		return HTL::IsValidService(m_h);
	}

	void Close()
	{
		// Close the handle
		if (IsValid())
		{
			BOOL b;
			b = ::CloseServiceHandle(m_h);
			_ASSERTE(b);
		}
		m_h = NULL;
	}

	bool operator!() const
	{
		return !IsValid();
	}

	operator SC_HANDLE() const
	{
		return m_h;
	}

	operator bool() const
	{
		return IsValid();
	}

	SC_HANDLE* operator&()
	{
		// The assert on operator& usually indicates a bug.	If this is really
		// what is needed, take the address of the m_h member explicitly

		_ASSERTE(!IsValid());
		return &m_h;
	}

	CServiceT<t_bManaged>& operator=
		( SC_HANDLE h
		)
	{
		// Try m_SCManager.Attach(other.Detach())
		// if you got an assertion here.

		_ASSERTE(!IsValid() || false == t_bManaged);
		m_h = h;
		return *this;
	}

	CServiceT<t_bManaged>& operator=
		( const CServiceT<true>& other
		)
	{
		// Avoid using this method,
		// use Attach(other.Detach() instead

		_ASSERTE(!IsValid() || false == t_bManaged);
		m_h = other.m_h;
		return *this;
	}

	CServiceT<t_bManaged>& operator=
		( const CServiceT<false>& other
		)
	{
		// Avoid using this method,
		// use Attach(other.Detach() instead

		_ASSERTE(!IsValid() || false == t_bManaged);
		m_h = other.m_h;
	}

	void Attach
		( IN SC_HANDLE h
		)
	{
		// The main difference between operator= & Attach
		// that Attach releases the handle.

		if (t_bManaged && IsValid())
			::CloseServiceHandle(m_h);
		m_h = h;
	}

	SC_HANDLE Detach()
	{
		SC_HANDLE h = m_h;
		m_h = NULL;
		return h;
	}

	BOOL ChangeConfig
		( IN DWORD dwServiceType
		, IN DWORD dwStartType
		, IN DWORD dwErrorControl
		, IN LPCSTR lpBinaryPathName = NULL
		, IN LPCSTR lpLoadOrderGroup = NULL
		, OUT LPDWORD lpdwTagId = NULL
		, IN LPCSTR lpDependencies = NULL
		, IN LPCSTR lpServiceStartName = NULL
		, IN LPCSTR lpPassword = NULL
		, IN LPCSTR lpDisplayName = NULL
		)
	{
		_ASSERTE(IsValid());
		return ::ChangeServiceConfigA(m_h, dwServiceType, dwStartType
			, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId
			, lpDependencies, lpServiceStartName, lpPassword, lpDisplayName);
	}

	BOOL ChangeConfig
		( IN DWORD dwServiceType
		, IN DWORD dwStartType
		, IN DWORD dwErrorControl
		, IN LPCWSTR lpBinaryPathName = NULL
		, IN LPCWSTR lpLoadOrderGroup = NULL
		, OUT LPDWORD lpdwTagId = NULL
		, IN LPCWSTR lpDependencies = NULL
		, IN LPCWSTR lpServiceStartName = NULL
		, IN LPCWSTR lpPassword = NULL
		, IN LPCWSTR lpDisplayName = NULL
		)
	{
		_ASSERTE(IsValid());
		return ::ChangeServiceConfigW(m_h, dwServiceType, dwStartType
			, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId
			, lpDependencies, lpServiceStartName, lpPassword, lpDisplayName);
	}

	BOOL ChangeConfig2A
		( IN DWORD dwInfoLevel
		, IN LPVOID lpInfo
		)
	{
		_ASSERTE(IsValid());
		return ::ChangeServiceConfig2A(m_h, dwInfoLevel, lpInfo);
	}

	BOOL ChangeConfig2W
		( IN DWORD dwInfoLevel
		, IN LPVOID lpInfo
		)
	{
		_ASSERTE(IsValid());
		return ::ChangeServiceConfig2W(m_h, dwInfoLevel, lpInfo);
	}

	BOOL ChangeConfig2
		( IN DWORD dwInfoLevel
		, IN LPVOID lpInfo
		)
	{
#ifdef UNICODE
		return ChangeConfig2W(dwInfoLevel, lpInfo);
#else
		return ChangeConfig2A(dwInfoLevel, lpInfo);
#endif
	}

	BOOL Control
		( IN DWORD dwControl
		, OUT LPSERVICE_STATUS lpServiceStatus
		)
	{
		_ASSERTE(IsValid());
		return ::ControlService(m_h, dwControl, lpServiceStatus);
	}

	BOOL ControlExA
		( IN DWORD dwControl
		, IN DWORD dwInfoLevel
		, IN OUT PVOID pControlParams
		)
	{
		_ASSERTE(IsValid());
		return ::ControlServiceExA(m_h, dwControl, dwInfoLevel, pControlParams);
	}

	BOOL ControlExW
		( IN DWORD dwControl
		, IN DWORD dwInfoLevel
		, IN OUT PVOID pControlParams
		)
	{
		_ASSERTE(IsValid());
		return ::ControlServiceExA(m_h, dwControl, dwInfoLevel, pControlParams);
	}

	BOOL ControlEx
		( IN DWORD dwControl
		, IN DWORD dwInfoLevel
		, IN OUT PVOID pControlParams
		)
	{
#ifdef UNICODE
		return ControlExW(dwControl, dwInfoLevel, pControlParams);
#else
		return ControlExA(dwControl, dwInfoLevel, pControlParams);
#endif
	}

	BOOL Delete()
	{
		_ASSERTE(IsValid());
		return ::DeleteService(m_h);
	}

	BOOL EnumDependentServices
		( IN DWORD dwServiceState
		, OUT LPENUM_SERVICE_STATUSA lpServices
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		, OUT LPDWORD lpServicesReturned
		)
	{
		_ASSERTE(IsValid());
		return ::EnumDependentServicesA(m_h, dwServiceState, lpServices, cbBufSize
			, pcbBytesNeeded, lpServicesReturned);
	}

	BOOL EnumDependentServices
		( IN DWORD dwServiceState
		, OUT LPENUM_SERVICE_STATUSW lpServices
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		, OUT LPDWORD lpServicesReturned
		)
	{
		_ASSERTE(IsValid());
		return ::EnumDependentServicesW(m_h, dwServiceState, lpServices, cbBufSize
			, pcbBytesNeeded, lpServicesReturned);
	}

	BOOL QueryConfig
		( OUT LPQUERY_SERVICE_CONFIGA lpServiceConfig
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		)
	{
		_ASSERTE(IsValid());
		return ::QueryServiceConfigA(m_h, lpServiceConfig, cbBufSize, pcbBytesNeeded);
	}

	BOOL QueryConfig
		( OUT LPQUERY_SERVICE_CONFIGW lpServiceConfig
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		)
	{
		_ASSERTE(IsValid());
		return ::QueryServiceConfigW(m_h, lpServiceConfig, cbBufSize, pcbBytesNeeded);
	}

	BOOL QueryConfig2A
		( IN DWORD dwInfoLevel
		, OUT LPBYTE lpBuffer
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		)
	{
		_ASSERTE(IsValid());
		return ::QueryServiceConfig2A(m_h, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
	}

	BOOL QueryConfig2W
		( IN DWORD dwInfoLevel
		, OUT LPBYTE lpBuffer
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		)
	{
		_ASSERTE(IsValid());
		return ::QueryServiceConfig2W(m_h, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
	}

	BOOL QueryConfig2
		( IN DWORD dwInfoLevel
		, OUT LPBYTE lpBuffer
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		)
	{
#ifdef UNICODE
		return QueryConfig2W(dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
#else
		return QueryConfig2A(dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
#endif
	}

	BOOL QueryObjectSecurity
		( IN SECURITY_INFORMATION dwSecurityInformation
		, OUT PSECURITY_DESCRIPTOR lpSecurityDescriptor
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		)
	{
		_ASSERTE(IsValid());
		return ::QueryServiceObjectSecurity(m_h, dwSecurityInformation
			, lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
	}

	BOOL QueryStatus
		( OUT LPSERVICE_STATUS lpServiceStatus
		)
	{
		_ASSERTE(IsValid());
		return ::QueryServiceStatus(m_h, lpServiceStatus);
	}

	BOOL QueryStatusEx
		( IN SC_STATUS_TYPE InfoLevel
		, OUT LPBYTE lpBuffer
		, IN DWORD cbBufSize
		, OUT LPDWORD pcbBytesNeeded
		)
	{
		_ASSERTE(IsValid());
		return ::QueryServiceStatusEx(m_h, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
	}

	BOOL SetObjectSecurity
		( IN SECURITY_INFORMATION dwSecurityInformation
		, IN PSECURITY_DESCRIPTOR lpSecurityDescriptor
		)
	{
		_ASSERTE(IsValid());
		return ::SetServiceObjectSecurity(m_h, dwSecurityInformation, lpSecurityDescriptor);
	}

	BOOL Start
		( IN DWORD dwNumServiceArgs
		, IN LPCSTR *lpServiceArgVectors
		)
	{
		_ASSERTE(IsValid());
		return ::StartServiceA(m_h, dwNumServiceArgs, lpServiceArgVectors);
	}

	BOOL Start
		( IN DWORD dwNumServiceArgs
		, IN LPCWSTR *lpServiceArgVectors
		)
	{
		_ASSERTE(IsValid());
		return ::StartServiceW(m_h, dwNumServiceArgs, lpServiceArgVectors);
	}

	DWORD NotifyStatusChange
		( IN DWORD dwNotifyMask
		, IN PSERVICE_NOTIFYA pNotifyBuffer
		)
	{
		_ASSERTE(IsValid());
		return ::NotifyServiceStatusChangeA(m_h, dwNotifyMask, pNotifyBuffer);
	}

	DWORD NotifyStatusChange
		( IN DWORD dwNotifyMask
		, IN PSERVICE_NOTIFYW pNotifyBuffer
		)
	{
		_ASSERTE(IsValid());
		return ::NotifyServiceStatusChangeW(m_h, dwNotifyMask, pNotifyBuffer);
	}
};

typedef CServiceT<true> CService;
typedef CServiceT<false> CServiceHandle;

/////////////////////////////////////////////////////////////////////////////

}	// namespace HTL

/////////////////////////////////////////////////////////////////////////////

#pragma warning(pop)

#endif	// #ifndef __HTLSVC_H__

/////////////////////////////////////////////////////////////////////////////
//	End Of File htlsvc.h
